FUNCTION INTREAD(VAR N: INTEGER): BOOLEAN;
VAR CH: CHAR;
BEGIN
  REPEAT  READ(KEYBOARD, CH)  UNTIL  (CH <> ' ') OR EOLN(KEYBOARD);
  IF CH IN DIGITSET THEN
    BEGIN
      N := 0;  INTREAD := TRUE;
      REPEAT
	N := 10*N+ORD(CH)-ORD0;  WRITE(OUTPUT, CH);  READ(KEYBOARD, CH);
      UNTIL (NOT (CH IN DIGITSET)) OR (N >= 3276);
    END
  ELSE  INTREAD := FALSE;
END; (* INTREAD *)


FUNCTION FINDPROC(SEGNUM, PROCNUM: BYTERANGE; STRTPLACE: DMSCWP;
		  VAR PPROCINFO, PLINKINFO: DMSCWP;
		  VAR LEVELSUP: INTEGER): BOOLEAN;
VAR FOUND: BOOLEAN;
BEGIN
  LEVELSUP := 0;
  PPROCINFO := STRTPLACE;
  PLINKINFO := PPROCINFO^.MSDYN;
  FOUND := (PPROCINFO^.MSJTAB^[JTABPROCANDLL].BYTEVAL[LOBYTE] = PROCNUM) AND
	   (PPROCINFO^.MSSEG^.BYTEVAL[LOBYTE] = SEGNUM);
  WHILE (NOT FOUND) AND (PLINKINFO^.MSDYN <> PLINKINFO) DO
    BEGIN
      LEVELSUP := LEVELSUP + 1;
      PPROCINFO := PLINKINFO;
      PLINKINFO := PPROCINFO^.MSDYN;
      FOUND := (PPROCINFO^.MSJTAB^[JTABPROCANDLL].BYTEVAL[LOBYTE] = PROCNUM) AND
	       (PPROCINFO^.MSSEG^.BYTEVAL[LOBYTE] = SEGNUM);
    END;
  FINDPROC := FOUND;
END; (* FINDPROC *)


PROCEDURE PUTCURSOR(LINE, COLUMN: INTEGER);
VAR I: INTEGER;
BEGIN
  WITH SYSCOM^, CRTCTRL, CRTINFO DO
    BEGIN
      IF ESCAPE = CHR(0) THEN WRITE(OUTPUT, HOME)
			 ELSE WRITE(OUTPUT, ESCAPE, HOME);
      WRITE(OUTPUT, COPY(ACROSSCHARS, 1, COLUMN), COPY(DOWNCHARS, 1, LINE));
    END
END; (*PUTCURSOR*)


PROCEDURE CLEARLINE(LINE: INTEGER);
BEGIN
  PUTCURSOR(LINE, 0);
  WITH SYSCOM^.CRTCTRL DO
    IF ESCAPE = CHR(0) THEN WRITE(OUTPUT, ERASEEOL)
		       ELSE WRITE(OUTPUT, ESCAPE, ERASEEOL)
END; (* CLEARLINE *)


PROCEDURE CLEARTHISLINE;
BEGIN
  WITH SYSCOM^.CRTCTRL DO
    IF ESCAPE =CHR(0) THEN WRITELN(OUTPUT, ERASEEOL)
		      ELSE WRITELN(OUTPUT, ESCAPE, ERASEEOL);
END;


PROCEDURE SPACEWAIT;
VAR CH: CHAR;
BEGIN
  REPEAT
    CLEARLINE(COMLINE);
    WRITE(OUTPUT, '......Hit [space] to continue......');
    READ(KEYBOARD, CH);
  UNTIL CH = ' ';
END;


PROCEDURE ERRORINDEBUGGER;
BEGIN
  CLEARLINE(PROMPTLINE+1);
  WRITELN(OUTPUT, 'I seem to have made a serious error and if you don''t mind,');
  WRITELN(OUTPUT, 'I am going to die peacefully.  .....AARGHHHHHH !!!!!!');
  EXIT(USERPROGRAM);
END; (* ERRORINDEBUGGER *)


FUNCTION GETPARAMS(VAR DSEGNUM: SEGRANGE; VAR DPROCNUM: BYTERANGE;
		   VAR OFFSET, DLNGTH: INTEGER;
		   VAR TPPROCINFO, TPLINKINFO: DMSCWP): BOOLEAN;
VAR JUNK: INTEGER;
BEGIN
  GETPARAMS := TRUE;
  DSEGNUM := SEGNUM;
  DPROCNUM := PROCNUM;
  OFFSET := -1;
  DLNGTH := LNGTH;
  TPPROCINFO := PPROCINFO;
  TPLINKINFO := PPROCINFO^.MSDYN;
  CLEARLINE(PROMPTLINE);
  WRITE(OUTPUT, 'Offset: ');
  IF INTREAD(OFFSET) THEN
      IF NOT EOLN(KEYBOARD) THEN
	BEGIN
	  WRITE(OUTPUT, '  Length: ');
	  IF INTREAD(DLNGTH) THEN
	    BEGIN
	      LNGTH := DLNGTH;
	      IF NOT EOLN(KEYBOARD) THEN
		BEGIN
		  WRITE(OUTPUT, '  Proc: ');
		  IF INTREAD(DPROCNUM) THEN
		    BEGIN
		      IF NOT EOLN(KEYBOARD) THEN
			BEGIN
			  WRITE(OUTPUT, '  Seg: ');
			  IF INTREAD(DSEGNUM) THEN;
			END;
		      IF NOT FINDPROC(DSEGNUM, DPROCNUM, PPROCINFO,
				      TPPROCINFO, TPLINKINFO, JUNK) THEN
			BEGIN
			  CLEARLINE(COMLINE);
			  WRITE(OUTPUT, 'Proc not found');
			  GETPARAMS := FALSE
			END
		    END
		END
	    END
	END
 END; (* GETPARAMS *)


PROCEDURE INITDEBUG;
VAR I: INTEGER;
    BUGTOSYS: RECORD CASE INTEGER OF
                0: (SYSDEBUG: ^INTEGER);
                1: (BUGDEBUG: ^BUGINFOREC)
              END;
BEGIN
  IF DEBUGINFO = NIL THEN  NEW(BUGDEBUGINFO);
  BUGTOSYS.BUGDEBUG := BUGDEBUGINFO;
  DEBUGINFO := BUGTOSYS.SYSDEBUG;
  FOR I := FIRSTDATALINE TO SYSCOM^.CRTINFO.HEIGHT-2 DO
    BUGDEBUGINFO^.SCREENINFO[I].LINETYPE := EMPTYLINE;
  BUGDEBUGINFO^.DATAPLACE := FIRSTDATALINE;
  BUGDEBUGINFO^.BUFFEREMPTY := TRUE;
  SYSCOM^.BUGSTATE := RUNNING;
  WRITELN(OUTPUT, 'PASCAL INTERACTIVE DEBUGGER - July 21, 1977');
END; (* INITDEBUG *)


PROCEDURE DISPLYSYSERROR;
VAR MSGNUM: INTEGER; MSG: STRING;
BEGIN
  MSGNUM := 0;
  PUTCURSOR(COMLINE, 0);
  CASE SYSCOM^.XEQERR OF
     1: MSG := 'INVALID INDEX - Subrange limits exceeded';
     3: MSG := 'Exitting from procedure never called';
     5: MSG := 'INTEGER OVERFLOW - ABS(<integer variable>) > maxint';
     6: MSG := 'DIVIDE BY ZERO'; 
     7: MSG := 'BAD MEMORY ADDRESS - Attempted access to a nil pointer';
     8: MSG := 'USER BREAK - Break character received';
     9: MSG := 'SYSTEM I/O ERROR';
    10: BEGIN
	       MSGNUM := ORD(SYSCOM^.IORSLT);
	       MSG := 'USER I/O ERROR - IORESULT =';
	       END;
    11: MSG := 'INTERPRETER ERROR - Instruction not implemented';
    12: MSG :=
'FLOATING POINT ERROR - Overflow, underflow, or divide by zero';
    13: MSG := 'STRING TOO LONG';
    14: MSG := 'USER BREAK POINT OR HALT - Unconditional HALT executed'
    END; (* CASE *)
  WRITE(OUTPUT, MSG);
  IF MSGNUM > 0 THEN WRITE(OUTPUT, MSGNUM);
END; (* DISPLYSYSERROR *)

PROCEDURE DISPLYMEM(WHAT: MEMTYPE; ADDR: INTEGER);
VAR I: INTEGER;  OUTSTRING: PACKED ARRAY [0..27] OF CHAR;
    TRICKSTUFF: MEMTYPE;  ADDRSTRING: PACKED ARRAY [0..8] OF CHAR;
BEGIN
  WITH TRICKSTUFF, OCTVAL DO
    BEGIN
      INTVAL := ADDR;
      FILLCHAR(ADDRSTRING, 3, ' ');
      ADDRSTRING[3+0] := CHR(FIRSTDIGIT+ORD0);
      ADDRSTRING[3+1] := CHR(FD0+ORD0);
      ADDRSTRING[3+2] := CHR(FD1+ORD0);
      ADDRSTRING[3+3] := CHR(FD2+ORD0);
      ADDRSTRING[3+4] := CHR(FD3+ORD0);
      ADDRSTRING[3+5] := CHR(FD4+ORD0);
    END;
  WITH WHAT DO
    BEGIN
      WRITE(OUTPUT, ADDRSTRING, INTVAL: 9);

      FILLCHAR(OUTSTRING, 28, ' ');
      WITH OCTVAL DO
	BEGIN
	  OUTSTRING[2+0] := CHR(FIRSTDIGIT+ORD0);
	  OUTSTRING[2+1] := CHR(FD0+ORD0);
	  OUTSTRING[2+2] := CHR(FD1+ORD0);
	  OUTSTRING[2+3] := CHR(FD2+ORD0);
	  OUTSTRING[2+4] := CHR(FD3+ORD0);
	  OUTSTRING[2+5] := CHR(FD4+ORD0);
	END;

      FOR I := HEXPERWORD DOWNTO 1 DO
	IF HEXVAL[I] < 10 THEN OUTSTRING[9+I] := CHR(HEXVAL[I]+ORD0)
	ELSE OUTSTRING[9+I] := CHR(HEXVAL[I]-10+ORD('A'));

      WITH BYTEOCTVAL DO
	BEGIN
	  OUTSTRING[15+1] := CHR(LD0+ORD0);
	  OUTSTRING[15+2] := CHR(LD1+ORD0);
	  OUTSTRING[15+3] := CHR(LD2+ORD0);
	  OUTSTRING[15+5] := CHR(HD0+ORD0);
	  OUTSTRING[15+6] := CHR(HD1+ORD0);
	  OUTSTRING[15+7] := CHR(HD2+ORD0);
	END;

      FOR I := 1 TO BYTESPERWORD DO
	IF CHARVAL[I] IN [' '..'~', ' '..'þ'] THEN
	  OUTSTRING[25+I] := CHARVAL[I]
	ELSE OUTSTRING[25+I] := SYSCOM^.CRTINFO.BADCH;

      WRITELN(OUTPUT, OUTSTRING);
    END
END; (* DISPLYMEM *)


PROCEDURE DISPLYHEADING;
BEGIN
  PUTCURSOR(HEADINGLINE, 0);
  WRITE(OUTPUT, 'TYPE     ID    PROC# OFFSET   ADDR   INTEGER');
  WRITE(OUTPUT, '   OCTAL   HEX   LO  HI  CHAR');
END; (* DISPLYHEADING *)


PROCEDURE DISPLYINFO;
VAR DATASZ, PARMSZ, STACKSZ, LL, IPC,
    PARENTNUM, PARENTLL, PARENTSEG,
    CALLER, CALLERLL, CALLSEG: INTEGER;
    TPPROCINFO, TPLINKINFO: DMSCWP;
BEGIN
  (* Info about current proc *)
  PROCNUM := PPROCINFO^.MSJTAB^[JTABPROCANDLL].BYTEVAL[LOBYTE];
  LL := PPROCINFO^.MSJTAB^[JTABPROCANDLL].BYTEVAL[HIBYTE];
  SEGNUM := PPROCINFO^.MSSEG^.BYTEVAL[LOBYTE];

  (* Info about parent *)
  TPLINKINFO := PLINKINFO^.MSSTAT;
  TPPROCINFO := PPROCINFO;
  WHILE TPPROCINFO^.MSDYN <> TPLINKINFO DO
    TPPROCINFO := TPPROCINFO^.MSDYN;
  PARENTNUM := TPPROCINFO^.MSJTAB^[JTABPROCANDLL].BYTEVAL[LOBYTE];
  PARENTLL := TPPROCINFO^.MSJTAB^[JTABPROCANDLL].BYTEVAL[HIBYTE];
  PARENTSEG := TPPROCINFO^.MSSEG^.BYTEVAL[LOBYTE];

  (* Info about caller *)
  CALLER := PLINKINFO^.MSJTAB^[JTABPROCANDLL].BYTEVAL[LOBYTE];
  CALLERLL := PLINKINFO^.MSJTAB^[JTABPROCANDLL].BYTEVAL[HIBYTE];
  CALLSEG := PLINKINFO^.MSSEG^.BYTEVAL[LOBYTE];

  (* More info on current proc *)
  STACKSZ := (ORD(PLINKINFO)-ORD(PPROCINFO^.MSSP)) DIV WORDSZ;
  DATASZ := (PPROCINFO^.MSJTAB^[JTABDATASZ].INTVAL) DIV BYTESPERWORD;
  PARMSZ := (PPROCINFO^.MSJTAB^[JTABPARMSZ].INTVAL) DIV BYTESPERWORD;
  IPC := PPROCINFO^.MSIPC - (ORD(PPROCINFO^.MSJTAB)+WORDSZ*JTABENTRIC
	 -PPROCINFO^.MSJTAB^[JTABENTRIC].INTVAL);
  PUTCURSOR(INFOLINE, 0);
  WRITELN(OUTPUT, 'PROC', PROCNUM: 4, '    CALLER', CALLER: 4, '    PARENT',
		PARENTNUM: 4, '    PARAM', PARMSZ: 4, '    DATA',
		DATASZ: 6);
  WRITELN(OUTPUT, ' SEG', SEGNUM: 4, '       SEG', CALLSEG: 4, '       SEG',
	       PARENTSEG: 4, '    STACK', STACKSZ: 4, '    IPC', IPC: 6,
	       '    DEPTH', LINKLEVEL: 3);
  WRITE(OUTPUT, '  LL', LL: 4, '        LL', CALLERLL: 4, '        LL',
	       PARENTLL: 4, '    DEFAULTLINK = ');
  PUTCURSOR(INFOLINE+2, LINKCOLUMN);
  IF LINKDEFAULT = DYNAMIC THEN WRITE(OUTPUT, 'DYNAMIC')
			   ELSE WRITE(OUTPUT, 'STATIC');
END; (* DISPLYINFO *)


PROCEDURE UPDATE;
VAR I, JUNK: INTEGER;
    TRICKSTUFF: MEMTYPE;
    TPPROCINFO, TPLINKINFO: DMSCWP;
BEGIN
  CLEARSCREEN;
  DISPLYSYSERROR;
  DISPLYINFO;
  DISPLYHEADING;
  PUTCURSOR(FIRSTDATALINE, 0);
  FOR I := FIRSTDATALINE TO LASTDATALINE DO
    WITH BUGDEBUGINFO^.SCREENINFO[I] DO
      BEGIN
	CASE LINETYPE OF
	    EMPTYLINE: WRITELN(OUTPUT);
	     DATALINE:  BEGIN
			  WRITE(OUTPUT, 'Data', PROC: 15, DISP: 7);
			  IF FINDPROC(SEG, PROC, PPROCINFO, TPPROCINFO,
				      TPLINKINFO, JUNK) THEN
			    DISPLYMEM(TPLINKINFO^.MSDATA[DISP],
				      ORD(TPLINKINFO)+DELTAMSCW
				      +(DISP-DATAOFFSET)*WORDSZ)
			  ELSE WRITELN(OUTPUT, '     Proc not found')
			END;
	    STACKLINE:  BEGIN
			  WRITE(OUTPUT, 'Stack', PROC: 14, DISP: 7);
			  IF FINDPROC(SEG, PROC, PPROCINFO, TPPROCINFO,
				      TPLINKINFO, JUNK) THEN
			    DISPLYMEM(TPPROCINFO^.MSSP^[DISP],
				      ORD(TPPROCINFO^.MSSP)+DISP*WORDSZ)
			  ELSE WRITELN(OUTPUT, '    Proc not found')
			END;
	  POINTERLINE:  BEGIN
			  WRITE(OUTPUT, 'Pntr', ' ': 22);
			  TRICKSTUFF.INTVAL := HEAPPOINTER;
			  DISPLYMEM(TRICKSTUFF.PTVAL^, HEAPPOINTER)
			END
	  END; (*CASE*)
      END; (*WITH*)
END; (*UPDATE*)


PROCEDURE DISPLYSTEPPINGINFO;
BEGIN
  UPDATE;
END;(* DISPLYSTEPPINGINFO *)

PROCEDURE DOEXAMINING;
VAR
  ENDCOMMAND: BOOLEAN;
  CH: CHAR;

  PROCEDURE TRAVERSELINKS(LINK: LINKTYPE; NLINKS: INTEGER;
			  DIRECTION: DIRECTYPE);
  BEGIN
    IF LINKDEFAULT = STATIC THEN
      IF DIRECTION = DOWN THEN
	BEGIN
	  CLEARLINE(COMLINE);
	  WRITE(OUTPUT,'Can only traverse UP Static links');
	END
      ELSE
	BEGIN (* So lets travel up the static links *)
	  WHILE (NLINKS>0) AND (PLINKINFO^.MSDYN<>PLINKINFO) DO
	    BEGIN
	      NLINKS := NLINKS-1;
	      PLINKINFO := PLINKINFO^.MSSTAT;
	    END;
	  IF PLINKINFO^.MSDYN = PLINKINFO THEN
	    BEGIN
	      CLEARLINE(COMLINE);
	      WRITE(OUTPUT,'Top of link chain');
	    END;
	  LINKLEVEL := 0;
	  PPROCINFO := JEXERRP;
	  WHILE PPROCINFO^.MSDYN <> PLINKINFO DO
	    BEGIN
	      PPROCINFO := PPROCINFO^.MSDYN;
	      LINKLEVEL := LINKLEVEL+1;
	    END;
	END (* of traveling up the Static links *)
    ELSE
      IF DIRECTION = DOWN THEN
	BEGIN  (* traveling down the Dynamic links *)
	  PPROCINFO := JEXERRP;
	  PLINKINFO := PPROCINFO^.MSDYN;
	  NLINKS := LINKLEVEL-NLINKS;
	  LINKLEVEL := 0;
	  IF NLINKS<=0 THEN
	    BEGIN
	      CLEARLINE(COMLINE);
	      WRITE(OUTPUT,'Bottom of link chain');
	    END
	  ELSE
	    TRAVERSELINKS(DYNAMIC, NLINKS, UP); (* We have now made it
		    look like it is going up the Dynamic links *)
	END  (*of going down the Dynamic links *)
      ELSE
	BEGIN  (* going up the Dynamic links *)
	  WHILE (NLINKS>0) AND (PLINKINFO^.MSDYN<>PLINKINFO) DO
	    BEGIN
	      LINKLEVEL := LINKLEVEL+1;
	      NLINKS := NLINKS-1;
	      PPROCINFO := PLINKINFO;
	      PLINKINFO := PPROCINFO^.MSDYN;
	    END;
	  IF PLINKINFO^.MSDYN = PLINKINFO THEN
	    BEGIN
	      CLEARLINE(COMLINE);
	      WRITE(OUTPUT, 'Top of link chain');
	    END;
	END; (*of traveling up the dynamic links *)
  END;(*TRAVERSELINKS*)


  PROCEDURE COMD;
  VAR DSEG, DPROC, OFFSET, LEN,
      DATANDPARMSZ, I, LINE: INTEGER;
      TPPROCINFO, TPLINKINFO: DMSCWP;
  BEGIN
    IF GETPARAMS (DSEG, DPROC, OFFSET, LEN, TPPROCINFO, TPLINKINFO) THEN
      BEGIN
	DATANDPARMSZ := (TPPROCINFO^.MSJTAB^[JTABDATASZ].INTVAL
			 + TPPROCINFO^.MSJTAB^[JTABPARMSZ].INTVAL)
			 DIV BYTESPERWORD;
	IF OFFSET = -1 THEN OFFSET := DATOFF;
	DATOFF := OFFSET + LEN;
	IF OFFSET-DATAOFFSET+1 > DATANDPARMSZ THEN
	  BEGIN
	    CLEARLINE(COMLINE);
	    WRITE(OUTPUT, 'Warning - offset too large');
	  END
	ELSE
	  IF OFFSET-DATAOFFSET+LEN > DATANDPARMSZ THEN
	    BEGIN
	      CLEARLINE(COMLINE);
	      WRITE(OUTPUT, 'Warning - length too large');
	    END;
      BUGDEBUGINFO^.BUFFEREMPTY := FALSE;
	LINE := BUGDEBUGINFO^.DATAPLACE;
	PUTCURSOR(LINE, 0);
	FOR I := OFFSET TO DATOFF-1 DO
	  WITH BUGDEBUGINFO^.SCREENINFO[LINE] DO
	    BEGIN
	      LINETYPE := DATALINE;
	      SEG := DSEG;
	      PROC := DPROC;
	      DISP := I;
	      WRITE(OUTPUT, 'Data', DPROC: 15, I: 7);
	      DISPLYMEM(TPLINKINFO^.MSDATA[I],
			ORD(TPLINKINFO)+DELTAMSCW+(I-DATAOFFSET)*WORDSZ);
	      IF LINE=LASTDATALINE THEN
		BEGIN LINE := FIRSTDATALINE; PUTCURSOR(LINE, 0) END
	      ELSE LINE := LINE + 1;
	    END;
	BUGDEBUGINFO^.DATAPLACE := LINE;
    END
  END; (* PROCEDURE COMD *)


  PROCEDURE COMS;
  VAR DSEG, DPROC, OFFSET, LEN,
      STACKSZ, I, LINE: INTEGER;
      TPPROCINFO, TPLINKINFO: DMSCWP;
  BEGIN
    IF GETPARAMS (DSEG, DPROC, OFFSET, LEN, TPPROCINFO, TPLINKINFO) THEN
      BEGIN
	STACKSZ := (ORD(TPLINKINFO) - ORD(TPPROCINFO^.MSSP)) DIV WORDSZ;
	IF OFFSET = -1 THEN OFFSET := STOFF;
	STOFF := OFFSET + LEN;
	IF OFFSET + 1 > STACKSZ THEN
	  BEGIN
	    CLEARLINE(COMLINE);
	    WRITE(OUTPUT, 'Warning - offset too large');
	  END
	ELSE
	  IF OFFSET + LEN > STACKSZ THEN
	    BEGIN
	      CLEARLINE(COMLINE);
	      WRITE(OUTPUT, 'Warning - length too large');
	    END;
	BUGDEBUGINFO^.BUFFEREMPTY := FALSE;
	LINE := BUGDEBUGINFO^.DATAPLACE;
	PUTCURSOR(LINE, 0);
	FOR I := OFFSET TO STOFF-1 DO
	  WITH BUGDEBUGINFO^.SCREENINFO[LINE] DO
	    BEGIN
	      LINETYPE := STACKLINE;
	      SEG := DSEG;
	      PROC := DPROC;
	      DISP := I;
	      WRITE(OUTPUT, 'Stack', DPROC:  14, I: 7);
	      DISPLYMEM(TPPROCINFO^.MSSP^[I], ORD(TPPROCINFO^.MSSP)+I*WORDSZ);
	      IF LINE = LASTDATALINE THEN
		BEGIN LINE := FIRSTDATALINE; PUTCURSOR(FIRSTDATALINE, 0) END
		ELSE LINE := LINE + 1;
	    END;
	BUGDEBUGINFO^.DATAPLACE := LINE;
    END
  END; (* PROCEDURE COMS *)


  PROCEDURE COMT;
  BEGIN
  END; (*COMT*)


  PROCEDURE COMB;
  BEGIN
  END; (*COMB*)


  PROCEDURE COME;
  VAR I: INTEGER;
  BEGIN
    BUGDEBUGINFO^.BUFFEREMPTY := TRUE;
    PUTCURSOR(FIRSTDATALINE, 0);
    FOR I := FIRSTDATALINE TO LASTDATALINE DO
      BEGIN  BUGDEBUGINFO^.SCREENINFO[I].LINETYPE := EMPTYLINE;  CLEARTHISLINE END;
    BUGDEBUGINFO^.DATAPLACE := FIRSTDATALINE;
  END; (* COME *)


  PROCEDURE COMH;
    BEGIN END;


  PROCEDURE MOVETOPROC;
  VAR PROC, SEG, LEVELS: INTEGER;
      CH: CHAR;
      TPLINKINFO, TPPROCINFO: DMSCWP;
  BEGIN
    SEG := SEGNUM;
    CLEARLINE(PROMPTLINE);
    WRITE(OUTPUT, 'Proc: ');
    IF NOT INTREAD(PROC) THEN
      BEGIN
	PPROCINFO := JEXERRP;
	PLINKINFO := PPROCINFO^.MSDYN;
	LINKLEVEL := 0;
	DISPLYINFO
      END
    ELSE
      BEGIN
	IF NOT EOLN(KEYBOARD) THEN
	  BEGIN
	    WRITE(OUTPUT, '  Seg: ');
	    IF INTREAD(SEG) THEN;
	  END;
	IF FINDPROC(SEG, PROC, PLINKINFO, TPPROCINFO, TPLINKINFO, LEVELS) THEN
	  BEGIN
	    LINKLEVEL := LINKLEVEL + LEVELS +1;
	    PPROCINFO := TPPROCINFO;
	    PLINKINFO := TPLINKINFO;
	    DISPLYINFO
	  END
	ELSE
	  BEGIN  CLEARLINE(COMLINE); WRITE(OUTPUT, 'Proc not found')  END;
      END;
  END;(*MOVETOPROC*)


  PROCEDURE INITEXAMINE;
VAR CH: CHAR;
  BEGIN
    SYSCOM^.BUGSTATE := EXAMINING;
    DIRECTION := UP;
    STOFF := 0;
    LNGTH := LASTDATALINE-FIRSTDATALINE+1;
    ENDCOMMAND := FALSE;
    WRITE(OUTPUT, 'Hit [space] when ready'); CH := GETCHAR(TRUE);
    UPDATE;
  END; (* INITEXAMINE *)

BEGIN (* DOEXAMINING *)
  INITEXAMINE;
  REPEAT
    CLEARLINE(PROMPTLINE);
    IF DIRECTION = DOWN THEN WRITE(OUTPUT, '<') ELSE WRITE(OUTPUT, '>');
    WRITELN(OUTPUT,
'EXAMINE: # links, <esc>, L(ink, D(ata, S(tack, M(ove, R(esume, C(rawl, W(alk');
    WRITE(OUTPUT,
'U(pdate, E(rase, <, >, H(eap ');
    CH := GETCHAR(FALSE);
    CLEARLINE(COMLINE);
    IF CH IN  ['<', '>', ',', '.', '0'..'9',
	       'B', 'C', 'D', 'E', 'H', 'L',
	       'M', 'R', 'S', 'T', 'U'] THEN
      CASE CH OF
      '>', '.': DIRECTION := UP;
      '<', ',': DIRECTION := DOWN;
	'0','1','2','3','4','5','6','7','8','9':
		BEGIN
		  TRAVERSELINKS(LINKDEFAULT,ORD(CH)-ORD0,DIRECTION);
		  DISPLYINFO;
		END;
	   'L':  BEGIN
		   PUTCURSOR(INFOLINE+2, LINKCOLUMN);
		   IF LINKDEFAULT = DYNAMIC THEN
		     BEGIN
		       LINKDEFAULT := STATIC;
		       WRITE(OUTPUT, 'STATIC ')
		     END
		   ELSE
		     BEGIN
		       LINKDEFAULT := DYNAMIC;
		       WRITE(OUTPUT, 'DYNAMIC')
		     END;
		 END;
	   'D': COMD;
	   'H': COMH;
	   'S': COMS;
	   'T': COMT;
	   'W': BEGIN
		  SYSCOM^.BUGSTATE := WALKING;
		  ENDCOMMAND := TRUE;
		END;
	   'C':  BEGIN
		   SYSCOM^.BUGSTATE := CRAWLING;
		   ENDCOMMAND := TRUE;
		 END;
	   'B': COMB;
	   'U': UPDATE;(*  Display *)
	   'R': BEGIN
		  SYSCOM^.BUGSTATE := RUNNING;
		  ENDCOMMAND:=TRUE;(* Resume Program *)
		END;
	   'M': MOVETOPROC;
	   'E': COME  (* Erase *)
      END (*CASE*)
    ELSE
      IF ORD(CH)  = ORDALT THEN  BEGIN CLEARSCREEN;  EXIT(USERPROGRAM) END
      ELSE
	IF EOLN(KEYBOARD) THEN
	  WITH BUGDEBUGINFO^ DO
	    BEGIN
	      CLEARLINE(DATAPLACE);
	      IF DATAPLACE = LASTDATALINE THEN DATAPLACE := FIRSTDATALINE
	      ELSE DATAPLACE := DATAPLACE + 1;
	    END
	ELSE BEGIN PUTCURSOR(COMLINE, 0); WRITE(OUTPUT, 'Not a command')  END;
  UNTIL ENDCOMMAND;
  CLEARSCREEN;
END; (* DOEXAMINE *)


PROCEDURE HANDLESTEPPING;
BEGIN
  IF SYSCOM^.XEQERR = 14 THEN  (* A HALT WAS EXECUTED *)
    DISPLYSTEPPINGINFO
  ELSE
    DOEXAMINING;
END;

PROCEDURE INITIALIZE;
VAR SYSTOBUG: RECORD CASE INTEGER OF
		0: (SYSMSCWP: MSCWP);
		1: (BUGMSCWP: DMSCWP);
  2: (SYSDEBUGINFO: ^INTEGER);
  3: (BUGDEBUGINFO: ^BUGINFOREC)
	      END; (* OLD TO NEW POINTER CONVERSION *)
    I, SIZE, DPROC, DSEG: INTEGER;
BEGIN
  DIGITSET := ['0'..'9'];
  SYSTOBUG.SYSMSCWP := SYSCOM^.BOMBP;
  JEXERRP := SYSTOBUG.BUGMSCWP;
  SYSTOBUG.SYSDEBUGINFO := DEBUGINFO;
  BUGDEBUGINFO := SYSTOBUG.BUGDEBUGINFO;
  PPROCINFO := JEXERRP;
  PLINKINFO := PPROCINFO^.MSDYN;
  LINKLEVEL := 0;
  LINKDEFAULT := DYNAMIC;

  COMLINE := SYSCOM^.CRTINFO.HEIGHT-1;
  LASTDATALINE := COMLINE-1;
  DATOFF := FIRSTDATAOFFSET;
  DOWNCHARS[0] := CHR(31);  ACROSSCHARS[0] := CHR(79); (* SET STRING LENGTHS *)
  FILLCHAR(DOWNCHARS[1], 31, CHR(10));
  FILLCHAR(ACROSSCHARS[1], 79, SYSCOM^.CRTCTRL.NDFS);

  IF BUGDEBUGINFO^.BUFFEREMPTY THEN
    BEGIN
      DPROC := PPROCINFO^.MSJTAB^[JTABPROCANDLL].BYTEVAL[LOBYTE];
      DSEG := PPROCINFO^.MSSEG^.BYTEVAL[LOBYTE];
      SIZE := (PPROCINFO^.MSJTAB^[JTABDATASZ].INTVAL
	       +PPROCINFO^.MSJTAB^[JTABPARMSZ].INTVAL) DIV BYTESPERWORD;
      IF SIZE > LASTDATALINE-FIRSTDATALINE+1 THEN
	SIZE := LASTDATALINE-FIRSTDATALINE+1;
      DATOFF := SIZE+DATAOFFSET;
      BUGDEBUGINFO^.DATAPLACE := FIRSTDATALINE+SIZE;
      IF BUGDEBUGINFO^.DATAPLACE>LASTDATALINE THEN
	BUGDEBUGINFO^.DATAPLACE := FIRSTDATALINE;
      FOR I := 0 TO SIZE-1 DO
	WITH BUGDEBUGINFO^.SCREENINFO[I+FIRSTDATALINE] DO
	  BEGIN
	    LINETYPE := DATALINE;
	    PROC := DPROC;
	    SEG := DSEG;
	    DISP := I+DATAOFFSET;
	  END;
      FOR I := SIZE+FIRSTDATALINE TO LASTDATALINE DO
	BUGDEBUGINFO^.SCREENINFO[I].LINETYPE := EMPTYLINE;
    END;
END; (* INITIALIZE *)

BEGIN (*SEGMENT PROCEDURE DEBUGGER *)
  IF SYSCOM^.BUGSTATE = ASLEEP THEN (*Lets wake up *)
    BEGIN
      INITDEBUG;
      EXECUTE(TRUE);
      SYSCOM^.BUGSTATE := ASLEEP
    END
  ELSE
    BEGIN
      INITIALIZE;
      IF SYSCOM^.XEQERR = 8 THEN (* he hit a break *)
	  CASE SYSCOM^.BUGSTATE OF
	    EXAMINING: BEGIN
			 CLEARLINE(COMLINE);
			 WRITE(OUTPUT,
'The <brk> key does not accomplish anything while in EXAMINE mode');
		       END;
	    CRAWLING, WALKING, RUNNING: DOEXAMINING
	  END (* CASE *)
      ELSE
	IF SYSCOM^.BUGSTATE = EXAMINING THEN ERRORINDEBUGGER
	ELSE
	    CASE SYSCOM^.BUGSTATE OF
	      CRAWLING: BEGIN
			  HANDLESTEPPING;
			  SPACEWAIT;
			END;
	       WALKING: HANDLESTEPPING;
	       RUNNING: DOEXAMING
	    END; (* CASE *)
      CLEARSCREEN;
    END; (* IF *)
END; (* SEGMENT PROCEDURE DEBUGGER *)



BEGIN (* PASCAL SYSTEM *) END.
